// 2014年版权归Go作者所有。版权所有。
// 此源代码的使用受BSD样式的约束
// 可以在许可证文件中找到的许可证。

// 包上下文定义上下文类型，该类型包含截止日期，
// 取消信号和其他跨越API边界的请求范围值
// 以及进程之间。
// None
// 对服务器的传入请求应创建上下文，而传出请求应创建上下文
// 对服务器的调用应接受上下文。功能链
// 它们之间的调用必须传播上下文，可以选择替换
// 它与使用WithCancel、WithDeadline、，
// WithTimeout或WithValue。取消上下文时，所有
// 从它派生的上下文也被取消。
// None
// WithCancel、WithDeadline和WithTimeout函数采用
// 上下文（父级）并返回派生上下文（子级）和
// 取消功能。调用CancelFunc将取消子项及其子项
// 子对象，删除父对象对子对象的引用，然后停止
// 任何相关的计时器。未能调用CancelFunc会泄漏
// 直到取消父项或计时器
// 开火。“go vet”工具会检查是否在所有计算机上使用了CancelFuncs
// 控制流动路径。
// None
// 使用上下文的程序应该遵循这些规则来保留接口
// 跨包保持一致，并支持静态分析工具检查上下文
// 传播：
// None
// 不要在结构类型中存储上下文；相反，传递一个上下文
// 显式地分配给每个需要它的函数。上下文应该是第一位的
// 参数，通常命名为ctx：
// None
// func DoSomething（ctx context.context，arg arg）错误{
// None
// }
// None
// 即使函数允许，也不要传递nil上下文。传递context.TODO
// 如果您不确定要使用哪个上下文。
// None
// 仅对传输进程和数据的请求范围数据使用上下文值
// API，不用于向函数传递可选参数。
// None
// 相同的上下文可以传递给在不同goroutine中运行的函数；
// 上下文对于多个goroutine同时使用是安全的。
// None
// 请参阅https:
// 上下文。
package context

import (
	"errors"
	"internal/reflectlite"
	"sync"
	"sync/atomic"
	"time"
)

// 上下文包含截止日期、取消信号和其他值
// API边界。
// None
// 多个goroutine可以同时调用上下文的方法。
type Context interface {
	// Deadline返回代表此上下文完成工作的时间
	// 应该取消。截止日期返回ok==无截止日期时为false
	// 设置连续调用Deadline返回相同的结果。
	Deadline() (deadline time.Time, ok bool)

	// Done返回一个通道，当代表该通道完成工作时，该通道关闭
	// 应该取消上下文。如果此上下文可以，则Done可能返回nil
	// 永远不要取消。连续调用Done返回相同的值。
	// 完成通道的关闭可能会异步进行，
	// 在cancel函数返回后。
	// None
	// WithCancel在调用cancel时安排关闭完成的操作；
	// WithDeadline安排在截止日期结束时完成
	// 到期；WithTimeout安排在超时时关闭“完成”
	// 过去了。
	// None
	// Done用于select语句：
	// None
	// None
	// None
	// func流（ctx context.context，out chan<-值）错误{
	// 为了{
	// v、 错误：=剂量计（ctx）
	// 如果出错！=零{
	// 返回错误
	// }
	// 挑选{
	// 案例<-ctx.Done（）：
	// 返回ctx.Err（）
	// 案例输出<-v：
	// }
	// }
	// }
	// None
	// 请参阅https:
	// 已完成的取消频道。
	Done() <-chan struct{}

	// 如果尚未关闭Done，Err将返回nil。
	// 如果关闭“完成”，Err将返回一个非零错误，解释原因：
	// 如果上下文已取消，则已取消
	// 或者如果上下文的截止日期已过，则超出死线。
	// Err返回非nil错误后，对Err的连续调用将返回相同的错误。
	Err() error

	// 值返回与键的此上下文关联的值，或为nil
	// 如果没有与键关联的值。连续调用值，使用
	// 相同的键返回相同的结果。
	// None
	// 仅对传输的请求范围的数据使用上下文值
	// 进程和API边界，不用于将可选参数传递给
	// 功能。
	// None
	// 键标识上下文中的特定值。希望实现的功能
	// 要在上下文中存储值，通常在全局
	// 变量，然后将该键用作context.WithValue和
	// Context.Value。键可以是支持相等的任何类型；
	// 包应将键定义为未报告的类型，以避免
	// 碰撞。
	// None
	// 定义上下文键的包应该提供类型安全的访问器
	// 对于使用该键存储的值：
	// None
	// None
	// 包用户
	// None
	// 导入“上下文”
	// None
	// None
	// 类型用户结构{…}
	// None
	// None
	// None
	// 类型键int
	// None
	// None
	// None
	// None
	// var用户密钥
	// None
	// None
	// func NewContext（ctx context.context，u*User）context.context{
	// 返回context.WithValue（ctx、userKey、u）
	// }
	// None
	// None
	// func FromContext（ctx context.context）（*用户，bool）{
	// u、 确定：=ctx.Value（userKey）。（*User）
	// 返回u，好吗
	// }
	Value(key interface{}) interface{}
}

// Cancelled是上下文返回的错误。取消上下文时出错。
var Canceled = errors.New("context canceled")

// DeadLineExcepended是上下文返回的错误。当上下文
// 截止日期过去了。
var DeadlineExceeded error = deadlineExceededError{}

type deadlineExceededError struct{}

func (deadlineExceededError) Error() string   { return "context deadline exceeded" }
func (deadlineExceededError) Timeout() bool   { return true }
func (deadlineExceededError) Temporary() bool { return true }

// emptyCtx从未取消，没有值，也没有截止日期。事实并非如此
// 结构{}，因为此类型的变量必须具有不同的地址。
type emptyCtx int

func (*emptyCtx) Deadline() (deadline time.Time, ok bool) {
	return
}

func (*emptyCtx) Done() <-chan struct{} {
	return nil
}

func (*emptyCtx) Err() error {
	return nil
}

func (*emptyCtx) Value(key interface{}) interface{} {
	return nil
}

func (e *emptyCtx) String() string {
	switch e {
	case background:
		return "context.Background"
	case todo:
		return "context.TODO"
	}
	return "unknown empty Context"
}

var (
	background = new(emptyCtx)
	todo       = new(emptyCtx)
)

// 后台返回一个非零的空上下文。它从来没有被取消过，也没有被取消过
// 值，并且没有截止日期。它通常由主功能使用，
// 初始化和测试，并作为传入
// 请求。
func Background() Context {
	return background
}

// TODO返回一个非零的空上下文。代码应在以下情况下使用context.TODO
// 尚不清楚要使用哪个上下文，或者它还不可用（因为
// 周围函数尚未扩展为接受上下文
// 参数）。
func TODO() Context {
	return todo
}

// CancelFunc通知操作放弃其工作。
// CancelFunc不会等待工作停止。
// 多个goroutine可以同时调用CancelFunc。
// 在第一次调用之后，对CancelFunc的后续调用不会执行任何操作。
type CancelFunc func()

// WithCancel返回具有新完成通道的父级副本。返回
// 调用返回的cancel函数时，上下文的Done通道关闭
// 或者当父上下文的“完成”通道关闭时，以先发生的为准。
// None
// 取消此上下文将释放与其关联的资源，因此代码应该
// 在此上下文中运行的操作完成后，立即调用cancel。
func WithCancel(parent Context) (ctx Context, cancel CancelFunc) {
	if parent == nil {
		panic("cannot create context from nil parent")
	}
	c := newCancelCtx(parent)
	propagateCancel(parent, &c)
	return &c, func() { c.cancel(true, Canceled) }
}

// newCancelCtx返回初始化的cancelCtx。
func newCancelCtx(parent Context) cancelCtx {
	return cancelCtx{Context: parent}
}

// goroutines统计曾经创建的goroutines的数量；用于测试。
var goroutines int32

// “传播取消”安排在父对象为时取消子对象。
func propagateCancel(parent Context, child canceler) {
	done := parent.Done()
	if done == nil {
		return // 父母永远不会被取消
	}

	select {
	case <-done:
		// 父项已被取消
		child.cancel(false, parent.Err())
		return
	default:
	}

	if p, ok := parentCancelCtx(parent); ok {
		p.mu.Lock()
		if p.err != nil {
			// 父项已被取消
			child.cancel(false, p.err)
		} else {
			if p.children == nil {
				p.children = make(map[canceler]struct{})
			}
			p.children[child] = struct{}{}
		}
		p.mu.Unlock()
	} else {
		atomic.AddInt32(&goroutines, +1)
		go func() {
			select {
			case <-parent.Done():
				child.cancel(false, parent.Err())
			case <-child.Done():
			}
		}()
	}
}

// &cancelCtxKey是cancelCtx返回自身的密钥。
var cancelCtxKey int

// parentCancelCtx返回父级的基础*cancelCtx。
// 它通过查找parent.Value（&cancelCtxKey）来查找
// 最里面的封闭*取消CTX，然后检查
// parent.Done（）与*cancelCtx匹配。（如果不是，则*cancelCtx
// 已包装在提供
// 不同的完成通道，在这种情况下，我们不应绕过它。）
func parentCancelCtx(parent Context) (*cancelCtx, bool) {
	done := parent.Done()
	if done == closedchan || done == nil {
		return nil, false
	}
	p, ok := parent.Value(&cancelCtxKey).(*cancelCtx)
	if !ok {
		return nil, false
	}
	pdone, _ := p.done.Load().(chan struct{})
	if pdone != done {
		return nil, false
	}
	return p, true
}

// removeChild从其父级移除上下文。
func removeChild(parent Context, child canceler) {
	p, ok := parentCancelCtx(parent)
	if !ok {
		return
	}
	p.mu.Lock()
	if p.children != nil {
		delete(p.children, child)
	}
	p.mu.Unlock()
}

// 取消器是可以直接取消的上下文类型。这个
// 实现是*cancelCtx和*timerCtx。
type canceler interface {
	cancel(removeFromParent bool, err error)
	Done() <-chan struct{}
}

// closedchan是一个可重复使用的封闭通道。
var closedchan = make(chan struct{})

func init() {
	close(closedchan)
}

// 可以取消取消CTX。取消时，它还会取消所有子项
// 那个机具取消器。
type cancelCtx struct {
	Context

	mu       sync.Mutex            // 保护以下字段
	done     atomic.Value          // 延迟创建的chan结构{}的，通过第一次取消调用关闭
	children map[canceler]struct{} // 第一次取消呼叫时设置为零
	err      error                 // 第一次取消呼叫时设置为非零
}

func (c *cancelCtx) Value(key interface{}) interface{} {
	if key == &cancelCtxKey {
		return c
	}
	return c.Context.Value(key)
}

func (c *cancelCtx) Done() <-chan struct{} {
	d := c.done.Load()
	if d != nil {
		return d.(chan struct{})
	}
	c.mu.Lock()
	defer c.mu.Unlock()
	d = c.done.Load()
	if d == nil {
		d = make(chan struct{})
		c.done.Store(d)
	}
	return d.(chan struct{})
}

func (c *cancelCtx) Err() error {
	c.mu.Lock()
	err := c.err
	c.mu.Unlock()
	return err
}

type stringer interface {
	String() string
}

func contextName(c Context) string {
	if s, ok := c.(stringer); ok {
		return s.String()
	}
	return reflectlite.TypeOf(c).String()
}

func (c *cancelCtx) String() string {
	return contextName(c.Context) + ".WithCancel"
}

// 取消关闭c.done，取消c的每个子项，如果
// removeFromParent为true，则从其父级的子级中移除c。
func (c *cancelCtx) cancel(removeFromParent bool, err error) {
	if err == nil {
		panic("context: internal error: missing cancel error")
	}
	c.mu.Lock()
	if c.err != nil {
		c.mu.Unlock()
		return // 已经取消
	}
	c.err = err
	d, _ := c.done.Load().(chan struct{})
	if d == nil {
		c.done.Store(closedchan)
	} else {
		close(d)
	}
	for child := range c.children {
		// 注意：在持有父锁的同时获取子锁。
		child.cancel(false, err)
	}
	c.children = nil
	c.mu.Unlock()

	if removeFromParent {
		removeChild(c.Context, c)
	}
}

// WithDeadline返回父上下文的副本，并调整截止日期
// 不迟于d。如果家长的截止日期早于d，
// WithDeadline（parent，d）在语义上等同于parent。返回
// 当截止日期到期时，当返回
// 调用cancel函数，或者在父上下文的Done通道
// 关闭，以先发生的为准。
// None
// 取消此上下文将释放与其关联的资源，因此代码应该
// 在此上下文中运行的操作完成后，立即调用cancel。
func WithDeadline(parent Context, d time.Time) (Context, CancelFunc) {
	if parent == nil {
		panic("cannot create context from nil parent")
	}
	if cur, ok := parent.Deadline(); ok && cur.Before(d) {
		// 目前的截止日期已经比新的截止日期早。
		return WithCancel(parent)
	}
	c := &timerCtx{
		cancelCtx: newCancelCtx(parent),
		deadline:  d,
	}
	propagateCancel(parent, c)
	dur := time.Until(d)
	if dur <= 0 {
		c.cancel(true, DeadlineExceeded) // 截止日期已经过去了
		return c, func() { c.cancel(false, Canceled) }
	}
	c.mu.Lock()
	defer c.mu.Unlock()
	if c.err == nil {
		c.timer = time.AfterFunc(dur, func() {
			c.cancel(true, DeadlineExceeded)
		})
	}
	return c, func() { c.cancel(true, Canceled) }
}

// timerCtx带有计时器和截止日期。它将一个cancelCtx嵌入到
// 实现完成并出错。它通过停止计时器来实现取消
// 授权取消ctx.cancel。
type timerCtx struct {
	cancelCtx
	timer *time.Timer // 在cancelCtx.mu下。

	deadline time.Time
}

func (c *timerCtx) Deadline() (deadline time.Time, ok bool) {
	return c.deadline, true
}

func (c *timerCtx) String() string {
	return contextName(c.cancelCtx.Context) + ".WithDeadline(" +
		c.deadline.String() + " [" +
		time.Until(c.deadline).String() + "])"
}

func (c *timerCtx) cancel(removeFromParent bool, err error) {
	c.cancelCtx.cancel(false, err)
	if removeFromParent {
		// 从其父级cancelCtx的子级中删除此timerCtx。
		removeChild(c.cancelCtx.Context, c)
	}
	c.mu.Lock()
	if c.timer != nil {
		c.timer.Stop()
		c.timer = nil
	}
	c.mu.Unlock()
}

// WithTimeout返回WithDeadline（父级，time.Now（）.Add（timeout））。
// None
// 取消此上下文将释放与其关联的资源，因此代码应该
// 在此上下文中运行的操作完成后，立即调用cancel：
// None
// func slowOperationWithTimeout（ctx context.context）（结果，错误）{
// ctx，cancel:=context.WithTimeout（ctx，100*time.毫秒）
// 推迟取消
// 返回慢操作（ctx）
// }
func WithTimeout(parent Context, timeout time.Duration) (Context, CancelFunc) {
	return WithDeadline(parent, time.Now().Add(timeout))
}

// WithValue返回父项的副本，其中与键关联的值为
// 瓦尔。
// None
// 仅对传输进程和数据的请求范围数据使用上下文值
// API，不用于向函数传递可选参数。
// None
// 提供的密钥必须具有可比性，且不应为
// 字符串或任何其他内置类型，以避免
// 使用上下文的包。WithValue的用户应该定义自己的
// 键的类型。在分配给时避免分配
// 接口{}，上下文键通常具有具体类型
// 结构{}。或者，导出的上下文键变量的静态
// 类型应该是指针或接口。
func WithValue(parent Context, key, val interface{}) Context {
	if parent == nil {
		panic("cannot create context from nil parent")
	}
	if key == nil {
		panic("nil key")
	}
	if !reflectlite.TypeOf(key).Comparable() {
		panic("key is not comparable")
	}
	return &valueCtx{parent, key, val}
}

// valueCtx携带一个键值对。它实现该键的值，并且
// 将所有其他调用委托给嵌入式上下文。
type valueCtx struct {
	Context
	key, val interface{}
}

// stringify尝试稍微stringify v，而不使用fmt，因为我们没有
// 希望上下文取决于unicode表。这只供用户使用
// *valueCtx.String（）。
func stringify(v interface{}) string {
	switch s := v.(type) {
	case stringer:
		return s.String()
	case string:
		return s
	}
	return "<not Stringer>"
}

func (c *valueCtx) String() string {
	return contextName(c.Context) + ".WithValue(type " +
		reflectlite.TypeOf(c.key).String() +
		", val " + stringify(c.val) + ")"
}

func (c *valueCtx) Value(key interface{}) interface{} {
	if c.key == key {
		return c.val
	}
	return c.Context.Value(key)
}
